/**
 * 
 */
package com.gragra.evaluateFunctionWords;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import com.gragra.data.Corpus;
import com.gragra.evaluateNouns.ExtendingSegmentation;
import com.gragra.functionalIdentification.FunctionalInsteadOfNoun;
import com.gragra.nounIdentification.BaseNounIdentifier;
import com.gragra.parseOptions.BooleanOption;
import com.gragra.parseOptions.CommandLineException;
import com.gragra.parseOptions.ListOfIntegerOption;
import com.gragra.parseOptions.ListOfStringsOption;
import com.gragra.parseOptions.Parser;
import com.gragra.sampling.sequentialStructure.ExtensionInformationValue;
import com.gragra.sampling.sequentialStructure.WordAndTagHolder;
import com.gragra.sampling.sequentialStructure.WordType;
import com.gragra.sequentiaDataGenerator.BaseGenerator;
import com.gragra.sequentiaDataGenerator.CaseLevelAssigningSegmenter;
import com.gragra.sequentiaDataGenerator.EmptySegmentation;
import com.gragra.sequentiaDataGenerator.PunctuationSplitOffSegmenter;
import com.gragra.sequentiaDataGenerator.Segmentation;
/**
 * @author Christoph Teichmann
 * 26.04.2013
 */
public class EvaluateFunctionsWithMapping
{
	/**
	 * 
	 */
	private int minCount = 1;
	/**
	 * 
	 */
	private final static String minCountOpt = "upTo";
	/**
	 * @return whether to microAverage
	 */
	public boolean isMicroAverage()
	{return this.microAverage;}
	/**
	 * 
	 */
	private final static String frameNumberOption = "nF";
	/**
	 * 
	 */
	private final static String wordNumberOption = "nW";
	/**
	 * 
	 */
	private final static String punctOffOption = "pO";
	/**
	 * 
	 */
	private final static String toLowerOption = "kU";
	/**
	 * 
	 */
	private static final String preMarkerOption = "preM";
	/**
	 * 
	 */
	private static final String postMarkerOption = "postM";
	/**
	 * 
	 */
	private int maxFrames = 10000;
	/**
	 * @return the postMarker
	 */
	public int getPostMarker()
	{return this.postMarker;}
	/**
	 * @return the preMarker
	 */
	public int getPreMarker()
	{return this.preMarker;}
	/**
	 * 
	 */
	private int maxWords = 100;
	/**
	 * 
	 */
	private static final String frameSizeOption = "fS";
	/**
	 * 
	 */
	private static final String relevantTagsOptions = "rT";
	/**
	 * 
	 */
	private int	frameSize = 3;
	/**
	 * 
	 */
	private boolean	microAverage = true;
	/**
	 * 
	 */
	private int	postMarker = 1;
	/**
	 * 
	 */
	private int	preMarker = 1;
	/**
	 * @return the frameSize
	 */
	public int getFrameSize()
	{return this.frameSize;}
	/**
	 * 
	 */
	private static final String macroOption = "mA";
	/**
	 * 
	 */
	private boolean toLowerCase = true;
	/**
	 * @return the toLowerCase
	 */
	public boolean isToLowerCase()
	{return this.toLowerCase;}
	/**
	 * @param toLowerCase the toLowerCase to set
	 */
	public boolean setToLowerCase(boolean toLowerCase)
	{return this.toLowerCase = toLowerCase;}
	/**
	 * 
	 */
	private String punctutationTag = null;
	/**
	 * 
	 * @param cl
	 * @param input
	 * @return
	 * @throws IOException
	 */
	public double[] evaluate(Parser cl,BufferedReader input) throws IOException
	{
		Object2ObjectOpenHashMap<String, ExtensionInformationValue> map = new Object2ObjectOpenHashMap<String, ExtensionInformationValue>();
		ListOfStringsOption lof = (ListOfStringsOption) cl.getInformation(relevantTagsOptions);
		String[] relevant = lof.getData();
		for(String s : relevant)
		{map.put(s,this.getRelevantClass());}
		setOptions(cl);
		Segmentation seg = this.punctutationTag != null ? new PunctuationSplitOffSegmenter(punctutationTag) : new EmptySegmentation();
		seg = this.isToLowerCase() ? new CaseLevelAssigningSegmenter(seg) : seg;
		seg = new ExtendingSegmentation(seg, map);
		BaseGenerator bg = new BaseGenerator(seg);
		Corpus<WordAndTagHolder> corp = bg.createCorpus(input);
		BaseNounIdentifier main = makeIdentifier(corp);
		main.identify();
		return main.evaluateOnSelf(microAverage);
	}
	/**
	 * @param corp
	 * @return
	 */
	protected BaseNounIdentifier makeIdentifier(
			Corpus<WordAndTagHolder> corp)
	{return new FunctionalInsteadOfNoun(corp, getFrameSize(), preMarker, postMarker, getMaxWords(), getMaxFrames(), this.getMinCount());}
	/**
	 * 
	 * @param cl
	 * @param input
	 * @param output
	 * @throws IOException
	 */
	public void writeOutWords(Parser cl, BufferedReader input, BufferedWriter output) throws IOException
	{
		FunctionalInsteadOfNoun main = initialize(cl, input);
		main.writeOutWords(output);
	}
	/**
	 * 
	 * @param cl
	 * @param input
	 * @param output
	 * @throws IOException
	 */
	public void writeOutFrames(Parser cl, BufferedReader input, BufferedWriter output) throws IOException
	{
		FunctionalInsteadOfNoun main = initialize(cl, input);
		main.writeOutFrames(output);
	}
	/**
	 * 
	 * @param cl
	 * @param input
	 * @param output
	 * @throws IOException
	 */
	public void annotate(Parser cl, BufferedReader input, BufferedWriter output) throws IOException
	{
		FunctionalInsteadOfNoun main = initialize(cl, input);
		main.annotateSelfWords();
		main.writeOutData(output);
	}
	/**
	 * @param cl
	 * @param input
	 * @return
	 * @throws IOException
	 */
	protected FunctionalInsteadOfNoun initialize(Parser cl, BufferedReader input)
			throws IOException
	{
		setOptions(cl);
		Segmentation seg = this.punctutationTag != null ? new PunctuationSplitOffSegmenter(punctutationTag) : new EmptySegmentation();
		seg = this.isToLowerCase() ? new CaseLevelAssigningSegmenter(seg) : seg;
		BaseGenerator bg = new BaseGenerator(seg);
		Corpus<WordAndTagHolder> corp = bg.createCorpus(input);
		FunctionalInsteadOfNoun main =  (FunctionalInsteadOfNoun) makeIdentifier(corp);
		main.identify();
		return main;
	}
	/**
	 * 
	 * @param cl
	 */
	private void setOptions(Parser cl)
	{
		ListOfIntegerOption loi = (ListOfIntegerOption) cl.getInformation(frameSizeOption);
		if(loi.hasBeenSet())
		{this.frameSize = loi.getSettings()[0];}
		BooleanOption bo = (BooleanOption) cl.getInformation(macroOption);
		if(bo.hasBeenSet())
		{this.microAverage = false;}
		loi = (ListOfIntegerOption) cl.getInformation(preMarkerOption);
		if(loi.hasBeenSet())
		{this.preMarker = (loi.getSettings()[0]);}
		loi = (ListOfIntegerOption) cl.getInformation(postMarkerOption);
		if(loi.hasBeenSet())
		{this.postMarker = (loi.getSettings()[0]);}
		this.setToLowerCase(true);
		bo = (BooleanOption) cl.getInformation(toLowerOption);
		if(bo.hasBeenSet())
		{this.setToLowerCase(false);}
		this.punctutationTag = null;
		bo = (BooleanOption) cl.getInformation(punctOffOption);
		if(bo.hasBeenSet())
		{this.punctutationTag = "PUNCT";}
		loi = (ListOfIntegerOption) cl.getInformation(frameNumberOption);
		if(loi.hasBeenSet())
		{this.setMaxFrames(loi.getSettings()[0]);}
		loi = (ListOfIntegerOption) cl.getInformation(wordNumberOption);
		if(loi.hasBeenSet())
		{this.setMaxWords(loi.getSettings()[0]);}
		loi = (ListOfIntegerOption) cl.getInformation(minCountOpt);
		if(loi.hasBeenSet())
		{this.setMinCount(loi.getSettings()[0]);}
	}
	/**
	 * 
	 * @return
	 */
	private ExtensionInformationValue getRelevantClass()
	{return WordType.Function;}
	/**
	 * 
	 * @param cl
	 * @return
	 * @throws CommandLineException 
	 */
	public Parser addOptions(Parser to) throws CommandLineException
	{
		to.addOption(relevantTagsOptions, new ListOfStringsOption("this option takes the list of all the tags" +
				" that will identify the relevant class"));
		to.setOptionNecessary(relevantTagsOptions);
		to.addOption(frameSizeOption, new ListOfIntegerOption("this options takes the size of the frame that will " +
				" be used"));
		to.addOption(preMarkerOption, new ListOfIntegerOption("this option can be used to set the amout of" +
				" padding markers that are added in front of the sentences," +
				" default is 0"));
		to.addOption(macroOption, new BooleanOption("set this option to true to enable macro-averaging for the evaluation"));
		to.addOption(postMarkerOption, new ListOfIntegerOption("this option can be used to set the amount of" +
				" post sentence padding that is used, default is 0"));
		to.addOption(wordNumberOption, new ListOfIntegerOption("this option can be used to set the number of function words that will be inferred"));
		to.addOption(frameNumberOption, new ListOfIntegerOption("this option can be used to set the number of function frames that will be inferred"));
		to.addOption(toLowerOption, new BooleanOption("if this option is set then strings will not be transferred to lower case"));
		to.addOption(punctOffOption, new BooleanOption("if this option is set then punctuation will be split off from words"));
		to.addOption(minCountOpt, new ListOfIntegerOption("sets the number of tags that will be used"));
		return to;
	}
	/**
	 * 
	 * @param cl
	 * @return
	 * @throws CommandLineException 
	 */
	public Parser addNoRelevantOptions(Parser to) throws CommandLineException
	{
		to.addOption(frameSizeOption, new ListOfIntegerOption("this options takes the size of the frame that will " +
				" be used"));
		to.addOption(preMarkerOption, new ListOfIntegerOption("this option can be used to set the amout of" +
				" padding markers that are added in front of the sentences," +
				" default is 0"));
		to.addOption(macroOption, new BooleanOption("set this option to true to enable macro-averaging for the evaluation"));
		to.addOption(postMarkerOption, new ListOfIntegerOption("this option can be used to set the amount of" +
				" post sentence padding that is used, default is 0"));
		to.addOption(wordNumberOption, new ListOfIntegerOption("this option can be used to set the number of function words that will be inferred"));
		to.addOption(frameNumberOption, new ListOfIntegerOption("this option can be used to set the number of function frames that will be inferred"));
		to.addOption(toLowerOption, new BooleanOption("if this option is set then strings will not be transferred to lower case"));
		to.addOption(punctOffOption, new BooleanOption("if this option is set then punctuation will be split off from words"));
		to.addOption(minCountOpt, new ListOfIntegerOption("sets the number of tags that will be used"));
		return to;
	}
	/**
	 * 
	 * @return
	 */
	public int getMaxFrames()
	{return maxFrames;}
	/**
	 * @param maxFrames the maxFrames to set
	 */
	private void setMaxFrames(int maxFrames)
	{this.maxFrames = maxFrames;}
	/**
	 * 
	 * @return
	 */
	public int getMaxWords()
	{return maxWords;}
	/**
	 * 
	 * @param maxWords
	 */
	private void setMaxWords(int maxWords)
	{this.maxWords = maxWords;}
	/**
	 * 
	 * @return
	 */
	public int getMinCount()
	{return minCount;}
	/**
	 * 
	 * @param minCount
	 */
	public void setMinCount(int minCount)
	{this.minCount = minCount;}
}